﻿/// MediaPlayer Sample
///
/// 2008 Keith Rome
///
/// Requires the Silverlight 1.0 Runtime Plugin


/// Region: Delegates and Instance-based Event Handlers
$delegate = function(instance, method) {
	return function() {
		return method.apply(instance, arguments);
	}
}
$attach = function(eventControl, eventName, targetObject, targetMethod)
{
    return eventControl.addEventListener(eventName,
        $delegate(targetObject, targetMethod));
}
$detach = function(eventControl, eventName, token)
{
    eventControl.removeEventListener(eventName, token);
}
/// EndRegion: Delegates and Instance-based Event Handlers


/// Region: JavaScript extensions
Array.prototype.indexOf = function (item)
{
    for (var ix = 0; ix < this.length; ix++)
        if (this[ix] == item)
            return ix;
    return -1;
}
Array.prototype.clear = function ()
{
    while (this.length > 0)
    {
        this.pop();
    }
}
/// EndRegion: JavaScript extensions


/// Region: "NameSpace" support
if (!window.SandBox)
{
    window.SandBox = {};
    window.SandBox.GeneratePlayerID = function()
    {
        if (!this.lastPlayerID)
        {
            this.lastPlayerID = 0;
        }
        this.lastPlayerID ++;
        return this.lastPlayerID.toString();
    }
}
/// EndRegion: "NameSpace" support


/// Region: MediaPlayer List
window.SandBox.RegisterPlayer = function(hostElementId, player)
{
    if (!this.players)
    {
        this.players = new Array();
    }
    this.players[hostElementId] = player;
}
window.SandBox.FindPlayer = function(hostElementId)
{
    return this.players[hostElementId];
}
$Player = window.SandBox.FindPlayer;
window.SandBox.StartPlayer = function(hostElementId, xamlFile, videoFile, bgColor)
{
    var player = new SandBox.MediaPlayer(hostElementId, xamlFile, videoFile, bgColor);
    player.Show();
}
/// EndRegion: MediaPlayer List


/// Region: MediaPlayer object
SandBox.MediaPlayer = function(hostElementId, xamlFile, videoFile, bgColor)
{
    SandBox.RegisterPlayer(hostElementId, this);
    this.xamlFile = xamlFile;
    this.videoFile = videoFile;
    this.bgColor = bgColor;
    this.hostElement = document.getElementById(hostElementId);
    this.plugin = null;
    this.rootXamlElement = null;
    this.defaultDownloader = null;
    this.playerId = SandBox.GeneratePlayerID();
    
    this.FindElement = function(elementName, root)
    {
        if (root != null)
        {
            var item = root.FindName(elementName);
            if (item != null)
            {
                return item;
            }
            var parent = root.GetParent();
            var expanded = this.FindElement(elementName, parent);
            if (expanded != null)
            {
                return expanded;
            }
        }
        return this.rootXamlElement.FindName(elementName);
    }
    
    this.CreateXaml = function(xaml)
    {
        return this.plugin.content.createFromXaml(xaml);
    }
    
    this.CreateXamlFromDownloader = function(partName, downloader)
    {
        if (downloader == null)
        {
            if (this.defaultDownloader == null)
            {
                return null;
            }
            else
            {
                return this.plugin.content.createFromXamlDownloader(this.defaultDownloader, partName);
            }
        }
        else
        {
            return this.plugin.content.createFromXamlDownloader(downloader, partName);
        }
    }

    this.Show = function()
    {
        Silverlight.createObjectEx({
            source: this.xamlFile,
            parentElement: this.hostElement,
            id: "SilverlightControl" + this.playerId,
            properties: {
                width: "100%",
                height: "100%",
                version: "1.0",
                isWindowless: "true",
                background: "Transparent"
            },
            events: {
                onLoad: $delegate(this, this.OnPluginLoaded)
            }
        });
    }
    
    this.OnPluginLoaded = function(control, userContext, rootElement)
    {
        this.plugin = control;
        this.rootXamlElement = rootElement;
        
        // capture startup values
        this.baseWidth = this.rootXamlElement.Width;
        this.baseHeight = this.rootXamlElement.Height;
        
        // wire up plugin events
        this.plugin.content.onResize = $delegate(this, this.OnPluginResized);
        this.plugin.content.onFullScreenChange = $delegate(this, this.OnPluginFullScreenChanged);
        
        // perform initial resizing
        this.PerformResize();
        
        // wire up the playback controls
        this.Controls = new SandBox.PlaybackControls(this.rootXamlElement);
        this.Controls.SetBackgroundColor(this.bgColor);
        
        // load video
        this.Controls.Load(this.videoFile);
    }
    
    this.PerformResize = function()
    {
        var currentWidth = this.plugin.content.actualWidth;
        var currentHeight = this.plugin.content.actualHeight;
        var widthGrowth = currentWidth / this.baseWidth;
        var heightGrowth = currentHeight / this.baseHeight;
        var smallerRatio = (widthGrowth < heightGrowth) ? widthGrowth : heightGrowth;
        
        var xForm = this.FindElement("ScaleXForm");
        xForm.ScaleX = smallerRatio;
        xForm.ScaleY = smallerRatio;
    }
    
    this.OnPluginResized = function(sender, eventArgs)
    {
        this.PerformResize();
    }
    
    this.OnPluginFullScreenChanged = function(sender, eventArgs)
    {
        this.PerformResize();
    }
}
/// EndRegion: MediaPlayer object


/// Region: Playback controls
SandBox.PlaybackControls = function(visualTree)
{
    // Find XAML objects
    this.XamlObjects =
    {
        Root: visualTree,
        VideoElement: visualTree.findName("VideoElement"),
        SkipForward: visualTree.findName("SkipForward"),
        SkipBackward: visualTree.findName("SkipBackward"),
        FrameForward: visualTree.findName("FrameForward"),
        FrameBackward: visualTree.findName("FrameBackward"),
        Play: visualTree.findName("Play"),
        Stop: visualTree.findName("Stop"),
        PlaybackTimer: visualTree.findName("PlaybackTimer"),
        Track: visualTree.findName("Track"),
        DownloadBar: visualTree.findName("DownloadBar"),
        ProgressBar: visualTree.findName("ProgressBar"),
        UpperThumbPart: visualTree.findName("UpperThumbPart"),
        LowerThumbPart: visualTree.findName("LowerThumbPart"),
        Thumb: visualTree.findName("Thumb"),
        MediaViewport: visualTree.findName("MediaViewport"),
        VideoScreen: visualTree.findName("VideoScreen"),
        PlaybackScreen: visualTree.findName("PlaybackScreen"),
        AudioControls: visualTree.findName("AudioControls"),
        Buttons: visualTree.findName("Buttons"),
        Progess: visualTree.findName("Progess"),
        TrackGel: visualTree.findName("TrackGel"),
        Vol0Bright: visualTree.findName("Vol0Bright"),
        Vol1Bright: visualTree.findName("Vol1Bright"),
        Vol2Bright: visualTree.findName("Vol2Bright"),
        Vol3Bright: visualTree.findName("Vol3Bright"),
        Vol4Bright: visualTree.findName("Vol4Bright"),
        Vol5Bright: visualTree.findName("Vol5Bright")
    }
    
    // init values
    this.XamlObjects.DownloadBar.Width = 0.0;
    this.XamlObjects.ProgressBar.Width = 0.0;
    this.XamlObjects.Vol0Bright.Tag = "0.0";
    this.XamlObjects.Vol1Bright.Tag = "0.2";
    this.XamlObjects.Vol2Bright.Tag = "0.4";
    this.XamlObjects.Vol3Bright.Tag = "0.6";
    this.XamlObjects.Vol4Bright.Tag = "0.8";
    this.XamlObjects.Vol5Bright.Tag = "1.0";
    this.upperThumbOffset = this.XamlObjects.UpperThumbPart["Canvas.Left"] - this.XamlObjects.Thumb["Canvas.Left"];
    this.lowerThumbOffset = this.XamlObjects.LowerThumbPart["Canvas.Left"] - this.XamlObjects.Thumb["Canvas.Left"];
    
    // exposed playback methods
    this.EnableControls = function(enable)
    {
        this.enabled = enable;
        
        this.XamlObjects.SkipForward.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.SkipBackward.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.FrameForward.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.FrameBackward.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Play.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Stop.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Thumb.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol0Bright.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol1Bright.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol2Bright.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol3Bright.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol4Bright.Cursor = enable ? "Hand" : "Default";
        this.XamlObjects.Vol5Bright.Cursor = enable ? "Hand" : "Default";
        
        if (enable)
        {
            this.UpdateDisplay();
        }
    }
    this.EnableControls(false);
    
    this.Load = function(videoFile)
    {
        this.XamlObjects.VideoElement.Source = videoFile;
        this.XamlObjects.PlaybackTimer.Begin();
    }
    
    this.UpdateDisplay = function()
    {
        this.XamlObjects.Vol1Bright.Opacity = (this.XamlObjects.VideoElement.Volume >= 0.2) ? "1" : "0";
        this.XamlObjects.Vol2Bright.Opacity = (this.XamlObjects.VideoElement.Volume >= 0.4) ? "1" : "0";
        this.XamlObjects.Vol3Bright.Opacity = (this.XamlObjects.VideoElement.Volume >= 0.6) ? "1" : "0";
        this.XamlObjects.Vol4Bright.Opacity = (this.XamlObjects.VideoElement.Volume >= 0.7) ? "1" : "0";
        this.XamlObjects.Vol5Bright.Opacity = (this.XamlObjects.VideoElement.Volume >= 1.0) ? "1" : "0";
    }
    
    this.SetBackgroundColor = function(newColor)
    {
        this.XamlObjects.VideoScreen.Fill.Color = newColor;
    }
    
    this.JumpToPosition = function(seconds)
    {
        if (seconds > this.XamlObjects.VideoElement.NaturalDuration.Seconds)
            seconds = this.XamlObjects.VideoElement.NaturalDuration.Seconds;
        var pos = this.XamlObjects.VideoElement.Position;
        pos.seconds = seconds;
        this.XamlObjects.VideoElement.Position = pos;
    }
    
    this.SeekFromCurrent = function(seconds)
    {
        var pos = this.XamlObjects.VideoElement.Position;
        var newTime = pos.seconds + seconds;
        this.JumpToPosition(newTime);
    }
    
    // video playback event handlers
    this.PlaybackHandlers =
    {
        Target: this,
        
        OnBufferingProgressChanged: function(sender, eventArgs)
        {
        },
        
        OnCurrentStateChanged: function(sender, eventArgs)
        {
        },
        
        OnDownloadProgressChanged: function(sender, eventArgs)
        {
            var progress = this.Target.XamlObjects.VideoElement.DownloadProgress;
            var trackPosition = progress * this.Target.XamlObjects.Track.Width;
            this.Target.XamlObjects.DownloadBar.Width = trackPosition;
        },
        
        OnMarkerReached: function(sender, eventArgs)
        {
        },
        
        OnMediaEnded: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.XamlObjects.VideoElement.Stop();
            this.Target.playing = false;
            this.Target.XamlObjects.Play.Visibility = "Visible";
            this.Target.XamlObjects.Stop.Visibility = "Collapsed";
        },
        
        OnMediaFailed: function(sender, eventArgs)
        {
            window.alert('Error loading Media File: ' + eventArgs.ErrorMessage);
        },
        
        OnMediaOpened: function(sender, eventArgs)
        {
            this.Target.EnableControls(true);
        }
    }
    
    // wire up the video playback handlers
    $attach(this.XamlObjects.VideoElement, "BufferingProgressChanged", this.PlaybackHandlers, this.PlaybackHandlers.OnBufferingProgressChanged);
    $attach(this.XamlObjects.VideoElement, "CurrentStateChanged", this.PlaybackHandlers, this.PlaybackHandlers.OnCurrentStateChanged);
    $attach(this.XamlObjects.VideoElement, "DownloadProgressChanged", this.PlaybackHandlers, this.PlaybackHandlers.OnDownloadProgressChanged);
    $attach(this.XamlObjects.VideoElement, "MarkerReached", this.PlaybackHandlers, this.PlaybackHandlers.OnMarkerReached);
    $attach(this.XamlObjects.VideoElement, "MediaEnded", this.PlaybackHandlers, this.PlaybackHandlers.OnMediaEnded);
    $attach(this.XamlObjects.VideoElement, "MediaFailed", this.PlaybackHandlers, this.PlaybackHandlers.OnMediaFailed);
    $attach(this.XamlObjects.VideoElement, "MediaOpened", this.PlaybackHandlers, this.PlaybackHandlers.OnMediaOpened);

    // Hover Effects event handlers
    this.HoverHandlers =
    {
        Target: this,
        
        OnMouseEnter: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            var baseName = sender.Name;
            var hoverEffectName = baseName + "Hover";
            var hoverEffect = this.Target.XamlObjects.Root.findName(hoverEffectName);
            hoverEffect.Opacity = 1;
        },
        
        OnMouseLeave: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            var baseName = sender.Name;
            var hoverEffectName = baseName + "Hover";
            var hoverEffect = this.Target.XamlObjects.Root.findName(hoverEffectName);
            hoverEffect.Opacity = 0;
        }
    }
    
    // wire up the Hover Effects handlers
    var attachHover = function(button, events)
    {
        $attach(button, "MouseEnter", events, events.OnMouseEnter);
        $attach(button, "MouseLeave", events, events.OnMouseLeave);
    }
    attachHover(this.XamlObjects.SkipForward, this.HoverHandlers);
    attachHover(this.XamlObjects.SkipBackward, this.HoverHandlers);
    attachHover(this.XamlObjects.FrameForward, this.HoverHandlers);
    attachHover(this.XamlObjects.FrameBackward, this.HoverHandlers);
    attachHover(this.XamlObjects.Play, this.HoverHandlers);
    attachHover(this.XamlObjects.Stop, this.HoverHandlers);

    // Playback Button event handlers
    this.ButtonHandlers =
    {
        Target: this,
        
        OnMarkerForward: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            var now = this.Target.XamlObjects.VideoElement.Position.Seconds;
            var closest = this.Target.XamlObjects.VideoElement.NaturalDuration.Seconds;
            for (marker in this.Target.XamlObjects.VideoElement.Markers)
            {
                if (marker.Time.Seconds > now)
                {
                    if (marker.Time.Seconds < closest)
                    {
                        closest = marker.Time.Seconds;
                    }
                }
            }
            this.Target.JumpToPosition(closest);
        },
        
        OnMarkerBackward: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            var now = this.Target.XamlObjects.VideoElement.Position.Seconds;
            var closest = 0.0;
            for (marker in this.Target.XamlObjects.VideoElement.Markers)
            {
                if (marker.Time.Seconds < now)
                {
                    if (marker.Time.Seconds > closest)
                    {
                        closest = marker.Time.Seconds;
                    }
                }
            }
            this.Target.JumpToPosition(closest);
        },
        
        OnFrameForward: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.SeekFromCurrent(10.0);
        },
        
        OnFrameBackward: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.SeekFromCurrent(-10.0);
        },
        
        OnPlay: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.XamlObjects.VideoElement.Play();
            this.Target.playing = true;
            this.Target.XamlObjects.Play.Visibility = "Collapsed";
            this.Target.XamlObjects.Stop.Visibility = "Visible";
        },
        
        OnStop: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.XamlObjects.VideoElement.Stop();
            this.Target.playing = false;
            this.Target.XamlObjects.Play.Visibility = "Visible";
            this.Target.XamlObjects.Stop.Visibility = "Collapsed";
        },
        
        OnPlaybackTimerCompleted: function(sender, eventArgs)
        {
            var now = this.Target.XamlObjects.VideoElement.Position.Seconds;
            var max = this.Target.XamlObjects.VideoElement.NaturalDuration.Seconds;
            
            var trackPosition = 0;
            
            if (max > 0)
            {
                trackPosition = (now / max) * this.Target.XamlObjects.Track.Width;
            }
            
            this.Target.XamlObjects.ProgressBar.Width = trackPosition;
            var thumbLeft = trackPosition - (this.Target.XamlObjects.Thumb["Width"] / 2.0);
            this.Target.XamlObjects.Thumb["Canvas.Left"] = thumbLeft;
            this.Target.XamlObjects.UpperThumbPart["Canvas.Left"] = thumbLeft + this.Target.upperThumbOffset;
            this.Target.XamlObjects.LowerThumbPart["Canvas.Left"] = thumbLeft + this.Target.lowerThumbOffset;
            
            this.Target.XamlObjects.PlaybackTimer.Begin();
        }
    }
    
    // wire up the Playback Button handlers
    $attach(this.XamlObjects.SkipForward, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnMarkerForward);
    $attach(this.XamlObjects.SkipBackward, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnMarkerBackward);
    $attach(this.XamlObjects.FrameForward, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnFrameForward);
    $attach(this.XamlObjects.FrameBackward, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnFrameBackward);
    $attach(this.XamlObjects.Play, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnPlay);
    $attach(this.XamlObjects.Stop, "MouseLeftButtonDown", this.ButtonHandlers, this.ButtonHandlers.OnStop);
    $attach(this.XamlObjects.PlaybackTimer, "Completed", this.ButtonHandlers, this.ButtonHandlers.OnPlaybackTimerCompleted);

    // Volume Control event handlers
    this.VolumeHandlers =
    {
        Target: this,
        
        OnVolumeSelect: function(sender, eventArgs)
        {
            if (!this.Target.enabled) { return; };

            this.Target.XamlObjects.VideoElement.Volume = sender.Tag;
            this.Target.UpdateDisplay();
        }
    }
    
    // wire up the Volume Control handlers
    $attach(this.XamlObjects.Vol0Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);
    $attach(this.XamlObjects.Vol1Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);
    $attach(this.XamlObjects.Vol2Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);
    $attach(this.XamlObjects.Vol3Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);
    $attach(this.XamlObjects.Vol4Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);
    $attach(this.XamlObjects.Vol5Bright, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnVolumeSelect);

    // Scrubbing event handlers
    this.VolumeHandlers =
    {
        Target: this,
        
        OnStartScrub: function(sender, eventArgs)
        {
            if (sender.CaptureMouse())
            {
                this.scrubbing = true;
                this.Target.XamlObjects.VideoElement.Pause();
            }
        },
        
        OnMoveScrub: function(sender, eventArgs)
        {
            if (this.scrubbing)
            {
                var ratio = eventArgs.GetPosition(this.Target.XamlObjects.Track).X / this.Target.XamlObjects.Track["Width"];
                var newPosition = ratio * this.Target.XamlObjects.VideoElement.NaturalDuration.Seconds;
                this.Target.JumpToPosition(newPosition);
            }
        },
        
        OnEndScrub: function(sender, eventArgs)
        {
            if (this.scrubbing)
            {
                var ratio = eventArgs.GetPosition(this.Target.XamlObjects.Track).X / this.Target.XamlObjects.Track["Width"];
                var newPosition = ratio * this.Target.XamlObjects.VideoElement.NaturalDuration.Seconds;
                this.Target.JumpToPosition(newPosition);
                this.scrubbing = false;
                sender.ReleaseMouseCapture();
                if (this.Target.playing)
                {
                    this.Target.XamlObjects.VideoElement.Play();
                }
            }
        }
    }
    
    // wire up the Scrubbing handlers
    $attach(this.XamlObjects.Thumb, "MouseLeftButtonDown", this.VolumeHandlers, this.VolumeHandlers.OnStartScrub);
    $attach(this.XamlObjects.Thumb, "MouseMove", this.VolumeHandlers, this.VolumeHandlers.OnMoveScrub);
    $attach(this.XamlObjects.Thumb, "MouseLeftButtonUp", this.VolumeHandlers, this.VolumeHandlers.OnEndScrub);
}
/// EndRegion: Playback controls
